@file:Suppress("HardwareIds", "DEPRECATION",
    "ApplySharedPref", "InternalInsetResource", "DelicateCoroutinesApi", "ObsoleteSdkInt")
package kotlinx.coroutines.script.tes

import android.app.Activity
import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Rect
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.Window
import android.view.WindowInsets
import android.view.WindowManager
import android.view.animation.AnimationUtils
import android.view.inputmethod.InputMethodManager
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView

import sample.ui.Properties
import abc.reflect.App
import com.netease.core.R
import com.google.gson.Gson
import com.hjq.permissions.XXPermissions
import com.hjq.toast.Toaster
import com.tencent.bugly.crashreport.CrashReport
import com.tendcloud.tenddata.TalkingDataSDK
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.script.Controller
import v9.assist.script.xLastEndLogoutTs
import java.io.Closeable
import java.io.File
import java.lang.reflect.Type
import java.security.MessageDigest
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.Random
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext


private var applicationContext: Context? = null
private var debugMode: Boolean? = null
fun initializeApp(context: Context, debug: Boolean = appIsDebug) {
    if (applicationContext != null) return
    applicationContext = context.applicationContext
    debugMode =  debug
    val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
    Thread.setDefaultUncaughtExceptionHandler { t, e ->
        analysisCrash(e)
        Properties.setControllerRunning(false)
        defaultUncaughtExceptionHandler?.uncaughtException(t, e)
    }
    TalkingDataSDK.init(context.applicationContext, "197673D9DB804DEEA6BC9817257ECB9B", if (isDebug) "debug" else "release", "")
    TalkingDataSDK.setGlobalKV("sysVersion", phoneVersionName)
    TalkingDataSDK.setGlobalKV("sysSdkInt", Build.VERSION.SDK_INT)
    TalkingDataSDK.setGlobalKV("sysScreenWidth", phoneScreenWidth)
    TalkingDataSDK.setGlobalKV("sysScreenHeight", phoneScreenHeight)
    TalkingDataSDK.setGlobalKV("sysDensityDpi", phoneDensityDpi)
    TalkingDataSDK.setReportUncaughtExceptions(true)
    CrashReport.initCrashReport(context.applicationContext, "443e68a2d5", true) //debug


    // Ocr.init()
    Toaster.init( context.applicationContext as Application)
    Toaster.setDebugMode(false)
    Toaster.setView(R.layout.toaster)
    Toaster.setGravity(Gravity.BOTTOM or Gravity.START)
//    Stab.t()

//    val rootBeer = RootBeer(context.applicationContext)
//    analysisEvent("环境Root_${rootBeer.isRooted}")
}

fun setupAnalysisUid(value: String?) {
    TalkingDataSDK.onLogin(value ?: appDeviceId, null)
    CrashReport.setUserId(value ?: appDeviceId)
}

//val appChannel by lazy {
//    val defaultValue = (if (isDebug) "debug" else (Build.BRAND ?: "default"))
//    WalleChannelReader.getChannel(appContext, defaultValue) ?: defaultValue
//}

val isDebug get() = debugMode ?: false
val appContext get() = applicationContext!!

fun printLog( msg: () -> String) {
    val output = "[${Thread.currentThread().name}-${Thread.currentThread().id}]${msg()}"
    if (isDebug) {
        Log.i("qweqweqwe", output)
    }
}
fun printLogE( msg: () -> String) {
    val output = "[${Thread.currentThread().name}-${Thread.currentThread().id}]${msg()}"
    if (isDebug) {
        Log.e("qweqweqwe", output)
    }
}

fun toast(msg: String?) {
    if (msg.isNullOrEmpty()) return
    runOnUIThread {
//        Toast.makeText(appContext, msg, Toast.LENGTH_LONG).show()
        Toaster.show(msg)
    }
}

fun clipBitmap(bitmap: Bitmap?, bounds: Rect): Bitmap? {
    if (bitmap  == null) return null
    return Bitmap.createBitmap(bitmap, bounds.left, bounds.top, bounds.width(), bounds.height())
}

fun Activity.useTranslucentStatusBar(statusBarLightMode: Boolean = false, navigationBarLightMode: Boolean = true) {
    StatusBarUtils.update(
        this, statusBarTranslucent = true, navigationBarTranslucent = true,
        statusBarLightMode = statusBarLightMode, navigationBarLightMode = navigationBarLightMode
    )
}

fun Activity.transformFullScreen() {
    requestWindowFeature(Window.FEATURE_NO_TITLE)
    window.setFlags(
        WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN
    )
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        try {
            window.insetsController?.hide(WindowInsets.Type.statusBars())
        } catch (_: Throwable) {}
    }
}

fun Activity.closeKeyboard(): Boolean {
    val imm = appContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    return currentFocus?.windowToken?.let { imm.hideSoftInputFromWindow(it, 0) } ?: false
}
fun DialogFragment.closeKeyboard(): Boolean {
    val imm = appContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    return dialog?.window?.currentFocus?.windowToken?.let { imm.hideSoftInputFromWindow(it, 0) } ?: false
}

private val mainHandler by lazy { Handler(Looper.getMainLooper()) }
fun runOnUIThread(block: () -> Unit) {
    if (Looper.getMainLooper() == Looper.myLooper()) block()
    else mainHandler.post(block)
}

//private val mmkv by lazy { MMKV.defaultMMKV() }
private val sharedPreference by lazy { appContext.getSharedPreferences("xza", Context.MODE_PRIVATE) }

fun writeToDisk(key: String, value: String?) {
//    if (isDebug) printLog { "writeToDisk key $key value $value" }
    sharedPreference.edit { putString(key, value) }
}

// androidx.core.content.SharedPreferences.kt
private inline fun SharedPreferences.edit(
    commit: Boolean = false,
    action: SharedPreferences.Editor.() -> Unit
) {
    val editor = edit()
    action(editor)
    if (commit) {
        editor.commit()
    } else {
        editor.apply()
    }
}

fun readByDisk(key: String): String? {
    return sharedPreference.getString(key, null)
//        .also { if (isDebug) printLog { "readByDisk key $key value $it" } }
}

val Int.dp
    get() = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        this.toFloat(),
        appContext.resources.displayMetrics
    ).toInt()
val Float.dp
    get() = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        this,
        appContext.resources.displayMetrics
    )

fun getColor(color: String): Int {
    return try {
        Color.parseColor(color)
    } catch (e: Throwable) {
        if (isDebug) e.printStackTrace()
        Color.TRANSPARENT
    }
}

val String?.md5: String
    get() {
        if (this.isNullOrEmpty()) return ""
        val sb = StringBuilder("")
        val digest = MessageDigest.getInstance("MD5")
        val md5ByteArray = digest.digest(toString().toByteArray())
        md5ByteArray.forEach {
            val hexString = Integer.toHexString(it.toInt() and 0xFF)
            if (hexString.length < 2) sb.append("0")
            sb.append(hexString)
        }
        return sb.toString()
    }



val Float?.percentage: String
    get() {
        if (this == null) return ""
        // https://blog.csdn.net/jlq_diligence/article/details/103955965
        val fmt = NumberFormat.getPercentInstance()
        fmt.maximumFractionDigits = 0
        return fmt.format(this)
    }

val View.activity: FragmentActivity? get() = getActivity(context) as? FragmentActivity?
private fun getActivity(context: Context?): Activity? {
    if (context == null) return null
    if (context is Activity) return context
    if (context is ContextWrapper) return getActivity(context.baseContext)
    return null
}

fun View.setOnClickCallback(interval: Long = 700L, callback: (View) -> Unit) {
    if (!isClickable) isClickable = true
    if (!isFocusable) isFocusable = true
    setOnClickListener(object : View.OnClickListener {
        override fun onClick(v: View?) {
            v ?: return
            val lastClickedTimestamp =
                v.getTag(R.id.view_last_click_timestamp)?.toString()?.toLongOrNull() ?: 0L
            val currTimestamp = System.currentTimeMillis()
            if (currTimestamp - lastClickedTimestamp < interval) {
                return
            }
            v.setTag(R.id.view_last_click_timestamp, currTimestamp)
            callback(v)
        }
    })
}
fun RecyclerView?.smoothScrollToBottom() {
    val self = this ?: return
    if (self.scrollState == RecyclerView.SCROLL_STATE_IDLE) {
        val itemCount = self.adapter?.itemCount ?: -1
        if (itemCount > 0) { // 比较靠进底部 再滑动到底部
            smoothScrollToPosition(itemCount - 1)
        }
    }
}


fun Context.requirePermission(permissions: List<String>, callback: () -> Unit) {
    XXPermissions.with(this)
        .permission(permissions)
        .request { _, all ->
            if (all) callback()
        }
}

private var swit: Int? = null
val systemWindowInsetsTop: Int get() = swit ?: 0 // for home page
fun initializeSystemWindowInsets() {
    if (swit == null) {
        var statusBarHeight = 0
        val resourceId = appContext.resources.getIdentifier("status_bar_height", "dimen", "android")
        if (resourceId > 0) {
            statusBarHeight = appContext.resources.getDimensionPixelSize(resourceId)
        }
        swit = statusBarHeight
    }
}


val String.colorInt: Int get() = getColor(this)

val View.lifecycleOwner: LifecycleOwner get() {
    val self = this
    var owner = self.getTag(R.id.view_lifecycle_owner) as? LifecycleOwner?
    if (owner == null) {
        val lifecycleOwner = object : LifecycleOwner {
            private val registry = LifecycleRegistry(this)
            override val lifecycle: LifecycleRegistry = registry
//            override fun getLifecycle(): LifecycleRegistry = registry
        }
        self.setTag(R.id.view_lifecycle_owner, lifecycleOwner)
        val viewLifecycle = lifecycleOwner.lifecycle
        owner = lifecycleOwner
        self.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {
                viewLifecycle.currentState = Lifecycle.State.CREATED
                viewLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START)
                viewLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
            }

            override fun onViewDetachedFromWindow(v: View) {
                viewLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
                viewLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
                viewLifecycle.currentState = Lifecycle.State.DESTROYED
                self.setTag(R.id.view_lifecycle_owner, null)
                self.removeOnAttachStateChangeListener(this)
            }
        })
    }
    return owner
}

fun <T> LiveData<T>.observe(view: View, observer: Observer<T>) {
    this.observe(view.lifecycleOwner, observer)
}

fun Long.toTime(pattern: String): String {
    return SimpleDateFormat(pattern, Locale.getDefault()).format(Date(this))
}

fun Closeable.closeQuietly() {
    try {
        close()
    } catch (rethrown: RuntimeException) {
        throw rethrown
    } catch (_: Exception) {
    }
}

fun appScopeLaunch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
) = GlobalScope.launch(context, start, block) // GlobalScope.launch(context + exceptionHandler, start, block)

val gson by lazy { Gson() }
fun <T> fromJson(json: String?, classOfT: Class<T>): T? {
    if (json.isNullOrEmpty()) return null
    return try {
        gson.fromJson(json, classOfT)
    } catch (e: Throwable) {
        if (isDebug) e.printStackTrace()
        null
    }
}
fun <T> fromJson(json: String?, typeOfT: Type): T? {
    if (json.isNullOrEmpty()) return null
    return try {
        gson.fromJson(json, typeOfT)
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

val Any.jsonString: String get() = gson.toJson(this)

val random by lazy { Random() }
fun Int.shake(edge: Int): Int {
    if (edge == 0) return this
    return this + (random.nextInt(edge) * if (random.nextBoolean()) 1 else -1)
}
fun Long.shake(edge: Int): Long {
    if (edge == 0) return this
    return this + (random.nextInt(edge) * if (random.nextBoolean()) 1 else -1)
}
fun Float.shake(edge: Int): Float {
    if (edge == 0) return this
    return this + (random.nextInt(edge) * if (random.nextBoolean()) 1 else -1)
}

fun View.startAnimationScaleKick() {
    startAnimation(AnimationUtils.loadAnimation(appContext, R.anim.scale_kick)!!)
}

val appVersionName by lazy {
    try {
        val packageInfo = appContext.packageManager.getPackageInfo(appContext.packageName, 0)
        packageInfo.versionName.toString()
    } catch (e: Throwable) { // PackageManager.NameNotFoundException
        if (isDebug) e.printStackTrace()
        ""
    }
}


//private val appDeviceIdDiskFile get() = File(FileUtils.filesDir("fps"), "out.txt")
//fun remarkAppDeviceIdInDisk() {
//    val newDeviceId = appOriginDeviceId
//    printLog { "remarkAppDeviceIdInDisk -> $newDeviceId" }
//    saveAppDeviceIdToDiskCache(newDeviceId)
//}
//private fun saveAppDeviceIdToDiskCache(deviceId: String) {
//    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
//        printLog { "readAppDeviceIdByDiskCache write disable P" }
//        return // 雷电9照旧
//    }
//    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.S_V2) {
//        printLog { "readAppDeviceIdByDiskCache write disable S_V2" }
//        return // mumu12照旧
//    }
//
//    val file = appDeviceIdDiskFile
//    val key = "immortal-white"
//    var toMakeNewKey = true
//    if (file.exists()) {
//        val value = FileUtils.syncRead(file)
//        val decrypted = AESUtils.decrypt(key, value)
//        if (decrypted.isNullOrEmpty()) {
//            printLog { "saveAppDeviceIdToDiskCache delete fake file 2" }
//            try { file.delete() } catch (_: Throwable) { }
//        } else {
//            val out = JSONObject(decrypted)
//            val ts = out.optLong("ts", 0)
//            val id = out.optString("id", "")
//            if (abs(file.lastModified() - ts) > 5000 || id != deviceId) {
//                printLog { "saveAppDeviceIdToDiskCache delete fake file" }
//                FileUtils.syncWrite(file, "") // 模拟器删不掉
//                try { file.delete() } catch (_: Throwable) { }
//            } else {
//                printLog { "saveAppDeviceIdToDiskCache [saved:$id][idByRule:$appOriginDeviceId]" }
//                toMakeNewKey = false
//            }
//        }
//    }
//    if (toMakeNewKey) {
//        val json = JSONObject()
//        json.put("ts", System.currentTimeMillis())
//        json.put("id", deviceId)
//        val encrypted = AESUtils.encrypt(key, json.toString())
//        printLog { "saveAppDeviceIdToDiskCache toMakeNewKey [${json}][data:${AESUtils.decrypt(key, encrypted)}][encrypted:$encrypted]" }
//        FileUtils.syncWrite(file, encrypted)
//    }
//}
//private fun readAppDeviceIdByDiskCache(): String? {
//    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
//        printLog { "readAppDeviceIdByDiskCache read disable P" }
//        return null // 雷电9照旧
//    }
//    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.S_V2) {
//        printLog { "readAppDeviceIdByDiskCache read disable S_V2" }
//        return null // mumu12照旧
//    }
//
//    val file = File(FileUtils.filesDir("fps"), "out.txt")
//    if (!file.exists()) return null
//    val key = "immortal-white"
//    val value = FileUtils.syncRead(file)
//    val decrypted = AESUtils.decrypt(key, value)
//    if (decrypted.isNullOrEmpty()) {
//        try { file.delete() } catch (_: Throwable) { }
//        return null
//    }
//    val out = JSONObject(decrypted)
//    val ts = out.optLong("ts", 0)
//    val id = out.optString("id", "")
//    return if (abs(file.lastModified() - ts) > 5000 || id.isNullOrEmpty()) {
//        printLog { "readAppDeviceIdByDiskCache delete fake file" }
//        try { file.delete() } catch (_: Throwable) { }
//        null
//    } else {
//        printLog { "readAppDeviceIdByDiskCache [saved:$id][idByRule:$appOriginDeviceId]" }
//        id
//    }
//}

val appDeviceId: String get() {
    return appOriginDeviceId
//    val cache = readAppDeviceIdByDiskCache()
//    return if (cache?.isNotEmpty() == true) cache
//    else appOriginDeviceId.also { saveAppDeviceIdToDiskCache(it) }
}

//val isEmulator by lazy {
//    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.S_V2) {
//        val eth0Address = FileUtils.syncRead(File("sys/class/net/eth0/address"))
//        if (eth0Address?.isNotEmpty() == true) return@lazy true
//        val wlan0Address = FileUtils.syncRead(File("sys/class/net/wlan0/address"))
//        if (wlan0Address?.isNotEmpty() == true) return@lazy true
//    } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
//        return@lazy true // 安卓9当雷电模拟器处理
//    }
//    return@lazy false
//}

val appOriginDeviceId: String get() {
    // 雷电9 // sdkInt 28 // Build.VERSION_CODES.P
    // mumu12L // sdkInt 32 // Build.VERSION_CODES.S_V2
    return if (Build.VERSION.SDK_INT == Build.VERSION_CODES.S_V2) {
        // val out = (System.currentTimeMillis().toString() + random.nextInt(10000)).md5
        val sb = StringBuilder()
        appAndroidId?.also { if (it.isNotEmpty()) sb.append(it) }
        val eth0Address = FileUtils.syncRead(File("sys/class/net/eth0/address"))
        sb.append(eth0Address)
        if (eth0Address == null || eth0Address == "null") {
            sb.append(FileUtils.syncRead(File("sys/class/net/wlan0/address")))
        }
        val out = sb.toString().md5
        printLog { "appOriginDeviceId in S_V2 $out  [androidId:$appAndroidId][${FileUtils.syncRead(File("sys/class/net/eth0/address"))}][${FileUtils.syncRead(File("sys/class/net/wlan0/address"))}]" }
        out
    } else {
        val sb = StringBuilder()
        appAndroidId?.also { if (it.isNotEmpty()) sb.append(it) } // 雷电9主要是androidId不一样
        // 雷电模拟器会调整这个 sb.append(Build.BOARD) // 获取设备基板名称        board:sdm710  #  board:k68v1_64
//        sb.append(Build.BOOTLOADER) // 获取设备引导程序版本号      bootloader:unknown  #  bootloader:unknown
//      和 FINGERPRINT 重复   sb.append(Build.ID) // 设备版本号。            id:OPM1.171019.026  #  id:PPR1.180610.011
        sb.append(Build.FINGERPRINT) // 雷电的都是一个值Android/graceltexx/gracelte:9/PQ3A.190705.09211555/G9700FXXU1APFO:user/release-keys  # 真机:设备的唯一标识。由设备的多个信息拼接合成。  fingerprint:Meizu/meizu_M1852_CN/M1852:8.1.0/OPM1.171019.026/1592244368:user/release-keys  #  fingerprint:vivo/PD1934/PD1934:9/PPR1.180610.011/compiler08081602:user/release-keys
        sb.append(Build.SERIAL) // serial:852QLDU223VEQ  #  serial:unknown
        val out = sb.toString().md5  //  ？？？  #  c2e70ecbf0bcf20ff9629a37cab58328
        printLog { "appOriginDeviceId in OTHER [${sb}]" }
        out
    }
}

val appVersionInfo: String get() {
    return "v.$appVersionName"
}

val appAndroidId: String? get() {
    return try { // SPLIT_BUNDLE 1006: Policy Declaration. (Advertising ID Android ID IMEI BSSID)
        Settings.Secure.getString(appContext.contentResolver, Settings.Secure.ANDROID_ID) // androidId:5b58675694ee5abb # androidId:51918d47df456a0e
    } catch (e: Throwable) {
        null
    }
}

// android id 不一样
val appDeviceInfo by lazy {
    val sb = StringBuilder()
    appAndroidId?.also { if (it.isNotEmpty()) sb.append("androidId:").append(appAndroidId).append("\n") }
    sb.append("board:").append(Build.BOARD).append("\n") // 获取设备基板名称
    sb.append("bootloader:").append(Build.BOOTLOADER).append("\n") // 获取设备引导程序版本号
    sb.append("brand:").append(Build.BRAND).append("\n") // 获取设备品牌
    sb.append("cpu_abi:").append(Build.CPU_ABI).append("\n") // 获取设备指令集名称（CPU的类型）
    sb.append("cpu_abi2:").append(Build.CPU_ABI2).append("\n") // 获取第二个指令集名称
    sb.append("device:").append(Build.DEVICE).append("\n") // 获取设备驱动名称
    sb.append("display:").append(Build.DISPLAY).append("\n") // 获取设备显示的版本包（在系统设置中显示为版本号）和ID一样
    sb.append("fingerprint:").append(Build.FINGERPRINT).append("\n") // 设备的唯一标识。由设备的多个信息拼接合成。
    sb.append("hardware:").append(Build.HARDWARE).append("\n") // 设备硬件名称,一般和基板名称一样（BOARD）
    sb.append("id:").append(Build.ID).append("\n")// 设备版本号。
    sb.append("model:").append(Build.MODEL).append("\n") // 获取手机的型号 设备名称。
    sb.append("manufacturer:").append(Build.MANUFACTURER).append("\n") // 获取设备制造商
    sb.append("product:").append(Build.PRODUCT).append("\n") // 整个产品的名称
    sb.append("tags:").append(Build.TAGS).append("\n") // 设备标签。如release-keys 或测试的 test-keys
    sb.append("type:").append(Build.TYPE).append("\n") // 设备版本类型 主要为 "user" 或 "eng".
    sb.append("user:").append(Build.USER).append("\n") // 设备用户名 基本上都为android -build
    sb.append("codename:").append(Build.VERSION.CODENAME).append("\n") // 设备当前的系统开发代号，一般使用REL代替
    sb.append("incremental:").append(Build.VERSION.INCREMENTAL).append("\n") // 系统源代码控制值，一个数字或者git hash值
    sb.append("serial:").append(Build.SERIAL).append("\n")
    sb.append("macEth0:").append(FileUtils.syncRead(File("sys/class/net/eth0/address"))).append("\n") // mumuMac
    sb.append("macWlan0:").append(FileUtils.syncRead(File("sys/class/net/wlan0/address"))).append("\n") // mumuMac
    sb.toString()
}

val phoneVersionName by lazy {
    when {
        Build.VERSION.SDK_INT >= 36 -> "16+"
        Build.VERSION.SDK_INT >= 35 -> "15"
        Build.VERSION.SDK_INT >= 34 -> "14"
        Build.VERSION.SDK_INT >= 33 -> "13"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2 -> "12L"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> "12"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> "11"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> "10"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> "9"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> "8.1"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> "8" // APP最小支持
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 -> "7.1"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> "7" //24
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> "6" //23
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 -> "5.1"
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> "5"
        else -> "<5"
    }
}




private fun isGameRunningExist(): Boolean? {
    // 游戏包名 auto.netease
    val am = appContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    var count = 0
    am.runningAppProcesses?.forEach {
         count++
         printLog { "runningProcess ${it.processName}" }
         // com.netease.g67.wyzymnqsd_cps
         // com.netease.g67.wyzymnqsd_cps:PushService
         if (it.processName.contains("com.netease.g67") && !it.processName.contains(":")) {
             return true
         }
     }
    return null // 不知道开了没. 雷电runningAppProcesses只返回自身
}
var lastLaunchTs = 0L
fun tryLaunchGame() {
    if (System.currentTimeMillis() - xLastEndLogoutTs < 60000) {
        printLog { "script. 已定时结束. 忽略重启游戏" }
        return
    }
    if (Controller.isRunning && System.currentTimeMillis() - lastLaunchTs < 20000) {
        printLog { "短时间内启动过游戏.稍后再看" }
        return
    }

    if (!Properties.tryLaunchAfterUnknown) {
        printLog { "script. 忽略自动启动游戏" }
        toast("已忽略自动打开游戏.请手动打开游戏")
        return
    }

    val gameExist = isGameRunningExist()
    if (gameExist != true) {
        try {
            val intent = Intent()
            intent.action = Intent.ACTION_VIEW
            intent.addCategory(Intent.CATEGORY_DEFAULT)
            intent.addCategory(Intent.CATEGORY_BROWSABLE)
            intent.data = Uri.parse("txm://launch/")
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            appContext.startActivity(intent)
            lastLaunchTs = System.currentTimeMillis()
        } catch (e: Throwable) {
            toast("找不到游戏本体，请通知管理员")
            e.printStackTrace()
        }
    }
}

fun View.setupTouchScaleAnimation() {
    setOnTouchListener { v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                v.animate().scaleX(0.94f).scaleY(0.94f).setDuration(150).start()
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                appScopeLaunch(Dispatchers.Main) {
                    delay(50)
                    v.animate().scaleX(1f).scaleY(1f).setDuration(150).start()
                }
            }
        }
        false
    }
    setOnClickListener {
    }
}


val appSessionIdDiskFile get() = File(FileUtils.filesDir("asidf"), "sess.txt")

// 给这个int 类型随机增加 4-5位小数
// 比如  3  返回 3.5425   // 其中 5425 是随机的
// 比如  6  返回 6.99743 // 其中 99743 是随机的
val Int.randomFloat: Float
    get() {
        // 生成 4-5 位随机小数
        val randomDecimal = (1000..99999).random() / 100000f
        // 将随机小数加到整数部分
        return this + randomDecimal
    }

fun Bitmap.takePixel(x: Int, y: Int): Int {
    // 下标越界返回-1
    return App.take().takePixel(this, x, y)
}



fun randomString(len: Int): String {
    var length = len
    val alphaNumericString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    val builder = java.lang.StringBuilder()
    while (length-- != 0) {
        val character = (Math.random() * alphaNumericString.length).toInt()
        builder.append(alphaNumericString[character])
    }
    return builder.toString()
}

val String.removeLastZero: String get() {
    if (this.endsWith(".0")) {
        return this.substring(0, this.length - 2)
    }
    return this
}